package com.utilcase.rabbitmq;

import com.rabbitmq.client.Channel;
import com.utilcase.domain.MessageLog;
import com.utilcase.enums.MessageStatus;
import com.utilcase.enums.OrderStatus;
import com.utilcase.service.MessageLogService;
import com.utilcase.service.OrdersService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * 死信队列消费者
 * 消息被拒绝、消息过期、队列达到最大长度限制等都会进入死信队列
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class DeadLetterQueueConsumer {
    private final MessageLogService messageLogService;
    private final OrdersService ordersService;

    @RabbitHandler
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = "order_dlx_queue"),//可以指定多种属性
                    exchange = @Exchange(value = "order_dlx_exchange"),
                    key = {"order.failed"}
            )
    }
    )
    public void receive(MessageLog message, Channel channel, Message msg) throws IOException {
        long deliveryTag = msg.getMessageProperties().getDeliveryTag();
        String orderId = message.getMessageId();
        log.info("order_dlx_queue死信队列接收到消息：{}，消息头信息：{}，消息头属性：{}", message, deliveryTag, msg.getMessageProperties());
        try {
            // 检查订单是否已经处理过 (幂等性处理)
            if (ordersService.checkOrderExists(Long.valueOf(message.getMessageId()))) {
                // 订单已处理，手动ack
                channel.basicAck(deliveryTag, false);
                return;
            }
            // 模拟异常
//            int i = 1 / 0;
            // 业务处理
            ordersService.updateStatus(orderId, OrderStatus.COMPLETED);
            // 查找并更新消息表状态 （逻辑删除消息表消息）
            messageLogService.updateStatus(orderId, MessageStatus.PROCESSED);
        } catch (Exception e) {
            ordersService.updateStatus(orderId, OrderStatus.FAILED);
            log.info("死信处理异常，消息处理失败交由定时任务处理");
            // 业务处理失败，定时任务查询MessageStatus.FAILED的消息进行重试
            messageLogService.updateStatus(orderId, MessageStatus.FAILED);
            //或者 死信队列重试
//            channel.basicNack(deliveryTag, false, true);
        }
    }
}